package repo

import (
	"errors"
	model "micro-oauth/datamodels"
	"micro-oauth/datamodels/params"
	"time"
)

func (s *ServiceImpl) GetAuthUserInfo(accessToken string) (userInfo *model.UserInfo, err error) {
	userInfo, err = s.cacheService.GetAuthUserInfo(accessToken)
	LogError(err, "get auth user from cache")
	if userInfo != nil {
		return userInfo, nil
	}
	token := s.GetToken(accessToken)
	if token == nil {
		return nil, errors.New("can not find token")
	}
	if token.ExpiresIn.Before(time.Now()) {
		return nil, errors.New("token expired")
	}
	user := s.GetUserById(token.UserId)
	if user == nil {
		return nil, errors.New("can not find user")
	}
	userInfo = &model.UserInfo{
		PartnerId: token.PartnerId,
		UserId:    token.UserId,
	}
	LogError(err, "userInfo calc sign fail")
	err = s.cacheService.SetAuthUserInfo(accessToken, userInfo, token.ExpiresIn)
	LogError(err, "set auth user from cache")
	return userInfo, nil
}

func (s *ServiceImpl) DeleteToken(tokenId uint64) error {
	return s.db.Unscoped().Where(
		"id = ?", tokenId,
	).Delete(model.Token{}).Error
}

func (s *ServiceImpl) AddToken(token *model.Token) error {
	return s.db.Create(token).Error
}

func (s *ServiceImpl) GetToken(accessToken string) *model.Token {
	var token model.Token
	err := s.db.Where("access_token = ?", accessToken).First(&token).Error
	if err != nil {
		return nil
	}
	return &token
}

func (s *ServiceImpl) UpdateToken(token *model.Token) error {
	err := s.db.Save(token).Error
	if err != nil {
		return err
	}
	return nil
}

func (s *ServiceImpl) ListToken(req *params.TokenListRequest) ([]*model.Token, error) {
	var tokens = make([]*model.Token, 0)
	db := s.db.Model(&model.Token{})
	db = s.db.Where("partner_id = ?", req.PartnerId)
	db = s.db.Where("scope_id = ?", req.ScopeId)
	if req.ClientId != 0 {
		db = db.Where("client_id = ?", req.ClientId)
	}

	if req.UserId != 0 {
		db = db.Where("user_id = ?", req.UserId)
	}
	if req.DeviceUUID != "" {
		db = db.Where("device_uuid = ?", req.DeviceUUID)
	}
	if req.Expired != nil {
		expired := *req.Expired
		if expired {
			db = db.Where("expires_in < ?", time.Now())
		} else {
			db = db.Where("expires_in >= ?", time.Now())
		}
	}
	err := db.Find(&tokens).Error
	if err != nil {
		return nil, err
	}
	return tokens, nil
}

func (s *ServiceImpl) DeleteTokens(opt *params.DeleteTokenOption) error {
	db := s.db.Where("partner_id = ?", opt.PartnerId)
	if opt.ScopeId != 0 { // product-ags user_info not invoke scope_id
		db = s.db.Where("scope_id = ?", opt.ScopeId)
	}

	if opt.DeviceUUID == "" && opt.UserId == 0 {
		return errors.New("must specific user_id or device_uuid")
	}
	if opt.UserId != 0 {
		db = db.Where("user_id = ?", opt.UserId)
	}
	if opt.DeviceUUID != "" {
		db = db.Where("device_uuid = ?", opt.DeviceUUID)
	}
	if opt.Expired != nil {
		expired := *opt.Expired
		if expired {
			db = db.Where("expires_in < ?", time.Now())
		} else {
			db = db.Where("expires_in >= ?", time.Now())
		}
	}
	return db.Delete(model.Token{}).Error
}
